use crate::context::Context;
use std::any::Any;
use std::future::Future;
use std::sync::Arc;

// Used to trigger events
pub trait EventTrigger: Any + Send + Sync {
    fn event_type_id(&self) -> u64;
}

impl<T: Any + Send + Sync> EventTrigger for T {
    fn event_type_id(&self) -> u64 {
        wd_tools::ptr::type_id::<T>()
    }
}
// EventHandle
#[async_trait::async_trait]
pub trait EventHandle: Send + Sync {
    fn event_type_id(&self) -> u64;
    async fn launch(
        &self,
        ctx: Context,
        req: Box<dyn EventTrigger>,
    ) -> anyhow::Result<Box<dyn EventTrigger>>;
}

// A registry and dispatch center for events
pub trait Schedule {
    fn schedule(&self, trigger_type_id: u64) -> Vec<Arc<dyn EventHandle>>;
}

// EventHandle's simple abstraction makes it easier to use and more secure
#[async_trait::async_trait]
pub trait AsyncHandle<T> {
    async fn call(&self, ctx: Context, arg: T) -> anyhow::Result<T>;
}

#[async_trait::async_trait]
impl<T, Trigger, F> AsyncHandle<Trigger> for T
where
    Trigger: EventTrigger,
    F: Future<Output = anyhow::Result<Trigger>> + Send,
    T: Fn(Context, Trigger) -> F + Send + Sync,
{
    async fn call(&self, ctx: Context, arg: Trigger) -> anyhow::Result<Trigger> {
        self(ctx, arg).await
    }
}
